package com.gdc.cloud.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.gdc.cloud.entities.CommonResult;
import com.gdc.cloud.entities.Payment;
import com.gdc.cloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * Description: 测试 Sentinel 熔断功能 Controller
 * @author: gdc
 * @date: 2022/5/23
 * @version 1.0
 */
@Slf4j
@RestController
public class CircleBreakerController {

    /**
     * 服务URL,为调用生产者端的应用名称
     */
    public static  final  String SERVICE_URL = "http://nacos-payment-provider";

    @Autowired
    private RestTemplate restTemplate;
    @Resource
    private PaymentService paymentService;

    /**
     * 服务调用者 -> 生产者支付接口
     *
     *  【1】http://localhost:84/consumer/fallback/4
     *      当ID=4,后台查询不到数据，此时由于没有兜底方案，前台会直接返回错误异常
     *  【2】http://localhost:84/consumer/fallback/4
     *      添加异常兜底方案时，当接口出现异常时，会调用异常兜底方案，此时展示信息为：
     *          {
     *              "code": 444,
     *              "message": "异常handlerFallback，exception内容： NullPointerException,该ID没有对应记录，空指针异常",
     *              "data": {
     *                  "id": 4,
     *                  "serial": "null"
     *              }
     *          }
     *  【3】http://localhost:84/consumer/fallback/1
     *      添加流控兜底方案时，当接口请求超出流控规则时，会调用流控的兜底方案
     *          {
     *              "code": 444,
     *              "message": "blockHandler-sentinel 限流，BlockException： null",
     *              "data": {
     *                  "id": 1,
     *                  "serial": "null"
     *              }
     *          }
     *  【4】 注解@SentinelResource，添加 exceptionsToIgnore = {IllegalArgumentException.class}  参数
     *      当对该异常忽略后，程序中出现的该异常，将不会在进行 fallback 的降级效果
     */
    @RequestMapping("/consumer/fallback/{id}")
    @SentinelResource(value = "fallback",
            fallback = "handlerFallback",
            blockHandler = "blockHandler",
            exceptionsToIgnore = {IllegalArgumentException.class}
        )
    public CommonResult<Payment> fallback(@PathVariable("id") Long id) {
        if(Objects.isNull(id)){
            // 添加 exceptionsToIgnore参数，并指定异常为：IllegalArgumentException
            throw new IllegalArgumentException("IllegalArgument ,非法参数异常...");
        }

        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/payment/" + id, CommonResult.class,id);

        if(Objects.isNull(result.getData())) {
            throw new NullPointerException("NullPointerException,该ID没有对应记录，空指针异常");
        }
        return  result;
    }


    /**
     * 添加 Feign 功能，测试服务降级功能
     */
    @GetMapping(value = "/consumer/paymentSql/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
        return paymentService.paymentSql(id);
    }

    /**
     * 异常兜底方案
     */
    public CommonResult handlerFallback(@PathVariable("id") Long id, Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult(444,"异常handlerFallback，exception内容： " + e.getMessage(), payment);
    }

    /**
     * 流控兜底解决方案
     */
    public CommonResult blockHandler(@PathVariable Long id, BlockException e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult(444,"blockHandler-sentinel 限流，BlockException： " + e.getMessage(), payment);
    }

}
